package com.pp.util.weixin;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.pp.util.weixin.bean.OAuthResult;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 用于微信公众号OAuth2.0鉴权，用户授权后获取授权用户唯一标识openid
 */
public class WxpubOAuth {




    /**
     * 获取微信公众号授权用户唯一标识
     * 通过code换取网页授权access_token
     *
     * @param appId     微信公众号应用唯一标识
     * @param appSecret 微信公众号应用密钥（注意保密）
     * @param code      授权code, 通过调用WxpubOAuth.createOauthUrlForCode来获取
     * @return OAuthResult   微信公众号授权用户唯一标识, 可用于微信网页内支付 等用户所有授权信息   此token不需要缓存 与基础token不同
     */
    public static OAuthResult getOpenId(String appId, String appSecret, String code)
            throws UnsupportedEncodingException {

        String url = WxpubOAuth.createOauthUrlForOpenid(appId, appSecret, code);

        String ret = WxpubOAuth.httpGet(url);
        OAuthResult oAuthResult = new Gson().fromJson(ret, OAuthResult.class);

        return oAuthResult;
    }

    /**
     * 获取用户基本信息
     */
    public static String getUserContent(String access_token, String openid, String lang)
            throws UnsupportedEncodingException {
        String url = WxpubOAuth.createGetUserUrlForOpenid(access_token, openid, lang);
        String ret = WxpubOAuth.httpGet(url);
        return ret;
    }

    /**
     * 用于获取授权code的URL地址，此地址用于用户身份鉴权，获取用户身份信息，同时重定向到$redirect_url
     *
     * @param appId       微信公众号应用唯一标识
     * @param redirectUrl 授权后重定向的回调链接地址，重定向后此地址将带有授权code参数， 该地址的域名需在微信公众号平台上进行设置， 步骤为：登陆微信公众号平台
     *                    开发者中心  网页授权获取用户基本信息 修改
     * @param moreInfo    FALSE 不弹出授权页面,直接跳转,这个只能拿到用户openid TRUE 弹出授权页面,这个可以通过 openid 拿到昵称、性别、所在地，
     * @return 用于获取授权code的URL地址
     */
    public static String createOauthUrlForCode(String appId, String redirectUrl, boolean moreInfo)
            throws UnsupportedEncodingException {
        Map<String, String> data = new HashMap<String, String>();
        data.put("appid", appId);
        data.put("redirect_uri", redirectUrl);
        data.put("response_type", "code");
        data.put("scope", moreInfo ? "snsapi_userinfo" : "snsapi_base");
        data.put("state", "STATE#wechat_redirect");
        String queryString = WxpubOAuth.httpBuildQuery(data);

        return "https://open.weixin.qq.com/connect/oauth2/authorize?" + queryString;
    }

    /**
     * 获取openid的URL地址
     *
     * @param appId     微信公众号应用唯一标识
     * @param appSecret 微信公众号应用密钥（注意保密）
     * @param code      授权code, 通过调用WxpubOAuth.createOauthUrlForCode来获取
     * @return 获取openid的URL地址
     */
    private static String createOauthUrlForOpenid(String appId, String appSecret, String code)
            throws UnsupportedEncodingException {
        Map<String, String> data = new HashMap<String, String>();
        data.put("appid", appId);
        data.put("secret", appSecret);
        data.put("code", code);
        data.put("grant_type", "authorization_code");
        String queryString = WxpubOAuth.httpBuildQuery(data);
        return "https://api.weixin.qq.com/sns/oauth2/access_token?" + queryString;
    }

    /**
     * 生成获取用户基本信息URL
     *
     * @param access_token 调用接口凭证
     * @param openid       普通用户的标识，对当前公众号唯一
     * @param lang         返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语
     * @return
     * @throws UnsupportedEncodingException
     */
    private static String createGetUserUrlForOpenid(String access_token, String openid, String lang) throws UnsupportedEncodingException {
        Map<String, String> data = new HashMap<String, String>();
        data.put("access_token", access_token);
        data.put("openid", openid);
        data.put("lang", lang);
        String queryString = WxpubOAuth.httpBuildQuery(data);

        return "https://api.weixin.qq.com/sns/userinfo?" + queryString;

    }

    public static String httpBuildQuery(Map<String, String> queryString) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> e : queryString.entrySet()) {
            if (sb.length() > 0) {
                sb.append('&');
            }
            sb.append(URLEncoder.encode(e.getKey(), "UTF-8")).append('=').append(URLEncoder.encode(e.getValue(), "UTF-8"));
        }

        return sb.toString();
    }

    /**
     * Http Get 请求
     */
    public static String httpGet(String urlString) {
        String result = "";
        try {
            URL url = new URL(urlString);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8"));
            String line;
            while ((line = rd.readLine()) != null) {
                result += line;
            }
            rd.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取微信公众号 jsapi_ticket
     */
    /*public   String getJsapiTicket(String appId, String appSecret) throws UnsupportedEncodingException {
        Map<String, String> data = new HashMap<String, String>();
        data.put("appid", appId);
        data.put("secret", appSecret);
        data.put("grant_type", "client_credential");
        String queryString = WxpubOAuth.httpBuildQuery(data);
        String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?" + queryString;
          //先从缓存中读access_token
        String resp= redis.get("WeChatAccess_token" );
        //缓存中不存在的时候
        if(resp== null){
            resp = httpGet(accessTokenUrl);
            //缓存微信 access_token
            redis.set("WeChatAccess_token", resp);
        }

        JsonParser jp = new JsonParser();
        JsonObject respJson = jp.parse(resp).getAsJsonObject();
        if (respJson.has("errcode")) {
            return respJson.toString();
        }

        data.clear();
        data.put("access_token", respJson.get("access_token").getAsString());
        data.put("type", "jsapi");
        queryString = WxpubOAuth.httpBuildQuery(data);
        String jsapiTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?" + queryString;
        resp = httpGet(jsapiTicketUrl);
        JsonObject ticket = jp.parse(resp).getAsJsonObject();
        return ticket.get("ticket").getAsString();
    }
    public    String getAccess_Token(String appId, String appSecret) throws UnsupportedEncodingException {
        Map<String, String> data = new HashMap<String, String>();
        data.put("appid", appId);
        data.put("secret", appSecret);
        data.put("grant_type", "client_credential");
        String queryString = WxpubOAuth.httpBuildQuery(data);
        String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?" + queryString;
        //先从缓存中读access_token
        String resp=(String) redis.get("WeChatAccess_token" );
        //缓存中不存在的时候
        if(resp== null){
            resp = httpGet(accessTokenUrl);
          Map map=  JSONObject.parseObject(resp,Map.class);
            //缓存微信 access_token
            resp=(String)map.get("access_token");
            redis.set("WeChatAccess_token" ,resp);
        }else{
            Map map=  JSONObject.parseObject(resp,Map.class);
            resp=(String)map.get("access_token");
        }
     return  resp;
    }*/
    /**
     * 生成微信公众号 js sdk signature
     */
    public static String getSignature(String nonceStr,String timeStamp, String jsapiTicket, String url) {
/*
        if (null == charge || null == jsapiTicket || charge.isEmpty() || jsapiTicket.isEmpty()) {
            return null;
        }

        JsonParser jp = new JsonParser();
        JsonObject chargeJson = jp.parse(charge).getAsJsonObject();
        if (!chargeJson.has("credential")) {
            return null;
        }
        JsonObject credential = chargeJson.get("credential").getAsJsonObject();
        if (!credential.has("wx_pub")) {
            return null;
        }

        JsonObject wx_pub = credential.get("wx_pub").getAsJsonObject();
*/

        String signature = "";
        //注意这里参数名必须全部小写，且必须有序
        String string1 = "jsapi_ticket=" + jsapiTicket +
                "&noncestr=" + nonceStr+
                "&timestamp=" +timeStamp +
                "&url=" + url;
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return signature;


    }
    //停止充电通知
  /*  public  static  String sendStopMessage(String openId,String order,String orderState,String useTime,String endTimem,String moeny) throws UnsupportedEncodingException {

        StopTenplateData stopTenplateData=new StopTenplateData();
        TenplateCss first=new TenplateCss();
        first.setColor("#173177");
        first.setValue("尊敬的用户，本次充电结束后结果如下：");
        TenplateCss key1=new TenplateCss();
        key1.setColor("#173177");
        key1.setValue(order);

        TenplateCss key2=new TenplateCss();
        key2.setColor("#173177");
        if(orderState.equals("4")){
            key2.setValue("已结束");
        }else{
            if(orderState.equals("3")){
                key2.setValue("停止中");
            }else{

                key2.setColor("#FF0000");
                key2.setValue("状态异常，订单状态代码："+orderState);
            }
        }


        TenplateCss key3=new TenplateCss();
        key3.setColor("#173177");
        key3.setValue(useTime);


        TenplateCss key4=new TenplateCss();
        key4.setColor("#173177");
        key4.setValue(endTimem);

        TenplateCss key5=new TenplateCss();
        key5.setColor("#173177");
        key5.setValue(moeny);

        stopTenplateData.setFirst(first);
        stopTenplateData.setKeyword1(key1);
        stopTenplateData.setKeyword2(key2);
        stopTenplateData.setKeyword3(key3);
        stopTenplateData.setKeyword4(key4);
        stopTenplateData.setKeyword5(key5);
        Map map=new HashMap<>();
        map.put("touser",openId);
        map.put("template_id",WxpubOAuth.stop_template_id);
        map.put("data",stopTenplateData);
        String  access_token= getAccess_Token(WxpubOAuth.APPID,WxpubOAuth.appSecret);
        String data= JSONObject.toJSONString(map);
        return  SendHttp.sendPost(WxpubOAuth.MessgeUrl+access_token,data);
    }

//启动充电桩通知
    public  static  String sendUseMessage(String openId,String order,String carPlant,String orderState,String useTime,String remarke) throws UnsupportedEncodingException {
        TenplateData tenplateData=new TenplateData();

        TenplateCss first=new TenplateCss();
        first.setValue("尊敬的用户，您本次充电信息凭证如下：");
        first.setColor("#173177");

        TenplateCss key1=new TenplateCss();
        key1.setValue(order);
        key1.setColor("#173177");
        TenplateCss key2=new TenplateCss();
        if(orderState.equals("2")){
           key2.setValue("启动成功。");
        }else{
            key2.setValue("启动出现错误，错误代码："+orderState);
        }
        key2.setColor("#173177");

        TenplateCss key3=new TenplateCss();
        key3.setValue(useTime);
        key3.setColor("#173177");
        TenplateCss remark=new TenplateCss();
        remark.setValue("点击查看订单详情或停止充电");
        remark.setColor("#173177");
        tenplateData.setFirst(first);
        tenplateData.setKeyword1(key1);
        tenplateData.setKeyword2(key2);
        tenplateData.setKeyword3(key3);
        tenplateData.setRemark(remark);

        Map map=new HashMap<>();
        map.put("touser",openId);
        map.put("template_id",WxpubOAuth.template_id);
        map.put("url",info_url+order+"&carPlant="+carPlant);
        map.put("data",tenplateData);
        String  access_token=getAccess_Token(WxpubOAuth.APPID,WxpubOAuth.appSecret);
        String data= JSONObject.toJSONString(map);
        return  SendHttp.sendPost(WxpubOAuth.MessgeUrl+access_token,data);
    }*/


    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    public static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }
    public static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}